package com.mengya.locks;

import java.util.concurrent.TimeUnit;

/**
 * @ClassName Lock8Demo
 * @Description 题目：谈谈你对多线程的理解
 * <p>
 * 线程 操作 资源类 8锁案例说明
 * 1. 标准访问有ab两个线程，请问先打印邮件还是短信                                               答案：sendEmail
 * 2. sendEmail方法暂停3秒钟，请问先打印邮件还是短信                                            答案：sendEmail
 * 3. 新增一个普通的hello方法，请问先打印邮件还是hello                                          答案：hello
 * 4. 两部手机，请问先打印邮件还是短信                                                         答案：sendSMS
 * 5. 两个静态同步方法，同1部手机，请问先打印邮件还是短信                                         答案：sendEmail
 * 6. 两个静态同步方法，2部手机，请问先打印邮件还是短信                                          答案：sendEmail
 * 7. 1个静态同步方法，1个普通同步方法，同1部手机，请问先打印邮件还是短信                           答案：sendSMS
 * 8. 1个静态同步方法，1个普通同步方法，2部手机，请问先打印邮件还是短信                             答案：sendSMS
 * <p>
 * <p>
 * 1-2
 * * * 一个对象里面如果有多个synchronized方法，某一个时刻内，只要一个线程去调用其中的一个synchronized方法
 * * * 其他的线程只能等待，换句话说，某一个时刻内，只能有唯一的一个线程去调用其中的一个synchronized方法
 * * * 锁的是当前对象this，被锁定后，其他的线程都不能进入到当前对象的其他的synchronized方法
 * <p>
 * 3-4
 * * * 加一个普通方法后发现和同步锁无关
 * * * 换成两个对象后，不是同一把锁了，情况立刻变化
 * <p>
 * 5-6 都换成静态同步方法后，情况又变化
 * * * 三种synchronized 锁的内容有一些差别：
 * * * 对于普通同步方法，锁的是当前实例对象，通常指this，具体的一部手机，所有的普通同步方法都是同一把锁---实例对象本身
 * * * 对于静态同步方法，锁的是当前类的class对象，如phone.class唯一的一个模板
 * * * 对于同步方法块，锁的是 synchronized 括号内的对象
 * <p>
 * 7-8
 * * * 当一个线程试图访问同步代码时，它首先必须得到锁，退出和抛出异常时必须释放锁。
 * * *
 * * * 所有的普通方法用的都是同一把锁----实例对象本身，就是new出来的具体实例对象本身，本类this
 * * * 也就是说如果一个实例对象的普通同步方法获取锁之后，该实例对象的其他普通方法必须等待获取锁的方法释放锁后才能获取锁
 * * *
 * * * 所有的静态同步方法用的也是同一把锁----类对象本身，就是我们说过的唯一模板class
 * * * 具体实例对象this和唯一模板class，这两把锁是两个不同的对象，所以静态同步方法与普通同步方法之间不会有竞态条件的
 * * * 但是一旦一个静态同步方法获取锁后，其他的静态同步方法都必须等待该方法释放锁后才能获取锁
 * @Author xiongwei.wu
 * @Date 2022/12/26 10:40
 **/
public class Lock8Demo {
    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        new Thread(() -> {
            phone.sendEmail();
        }, "a").start();
//        try { TimeUnit.MILLISECONDS.sleep(200); } catch (InterruptedException exception) { exception.printStackTrace(); }
//        new Thread(phone::hello, "b").start();
        new Thread(() -> {
//            phone.sendSMS();
            phone2.sendSMS();
        }, "b").start();
    }
}

class Phone {
    public static synchronized void sendEmail() {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException exception) {
            exception.printStackTrace();
        }
        System.out.println("----------sendEmail");
    }

    public synchronized void sendSMS() {
        System.out.println("----------sendSMS");
    }

    public void hello() {
        System.out.println("----------hello");
    }
}
